package request

import (
	"bytes"
	"encoding/json"
	"io"
	"lark/src/object"
	"net/http"
	"net/url"
	"time"
)

// Request 表示一个HTTP请求
type Request struct {
	Method  string            // HTTP方法: GET, POST, PUT, DELETE等
	URL     string            // 请求URL
	Headers map[string]string // 请求头
	Body    []byte            // 请求体
	Query   string            // 查询参数
	Timeout int               // 请求超时时间(秒)
}

// Response 表示HTTP响应
type Response struct {
	StatusCode int               // HTTP状态码
	Status     string            // 状态文本
	Headers    map[string]string // 响应头
	Body       []byte            // 响应体(字符串)
	Duration   float64           // 请求耗时(秒)
	Error      string            // 错误信息
}

// NewRequest 创建一个新的请求对象
func newRequest(method, url string) *Request {
	return &Request{
		Method:  method,
		URL:     url,
		Headers: make(map[string]string),
		Query:   "",
		Timeout: 30, // 默认30秒超时
	}
}

// SetHeader 设置请求头
func (r *Request) SetHeader(key, value string) *Request {
	r.Headers[key] = value
	return r
}

// SetQuery 设置查询参数
func (r *Request) SetQuery(key, value string) *Request {
	// r.Query.Add(key, value)
	return r
}

// SetBody 设置请求体
func (r *Request) SetBody(data []byte) *Request {
	r.Body = data
	return r
}

// SetJSONBody 设置JSON格式的请求体
func (r *Request) SetJSONBody(data interface{}) (*Request, error) {
	jsonData, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	r.SetHeader("Content-Type", "application/json")
	r.Body = jsonData
	return r, nil
}

// SetTimeout 设置请求超时时间
func (r *Request) SetTimeout(seconds int) *Request {
	r.Timeout = seconds
	return r
}

// Send 发送HTTP请求
func (r *Request) send() (*Response, error) {
	// 构建完整URL
	u, err := url.Parse(r.URL)
	if err != nil {
		return nil, err
	}
	// u.RawQuery = r.Query.Encode()
	startTime := time.Now()
	// 创建HTTP请求
	req, err := http.NewRequest(r.Method, u.String(), bytes.NewBuffer(r.Body))
	if err != nil {
		return nil, err
	}

	// 设置请求头
	for key, value := range r.Headers {
		req.Header.Set(key, value)
	}

	// 创建带超时的HTTP客户端
	client := &http.Client{
		Timeout: time.Duration(r.Timeout) * time.Second,
	}

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return &Response{Error: err.Error()}, nil
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return &Response{Error: err.Error()}, nil
	}

	// 构建响应对象
	response := &Response{
		StatusCode: resp.StatusCode,
		Status:     resp.Status,
		Body:       body,
		Headers:    make(map[string]string),
	}

	// 复制响应头
	for key, values := range resp.Header {
		if len(values) > 0 {
			response.Headers[key] = values[0]
		}
	}
	response.Duration = time.Since(startTime).Seconds()

	return response, nil
}

// Get 快捷方法: 发送GET请求
/* func wrapGet(url string) (*Response, error) {
	return NewRequest("GET", url).Send()
} */
func wrapGet(args ...object.Object) object.Object {
	return &object.Builtin{
		Fn: func(args ...object.Object) object.Object {
			url, ok := args[0].(*object.String)
			if !ok {
				return &object.Error{Message: "url参数不能为空"}
			}
			result, err := newRequest("GET", url.Value).send()
			if err != nil {
				return &object.Error{Message: err.Error()}
			}
			return &object.HttpResponse{
				StatusCode: result.StatusCode,
				Status:     result.Status,
				Headers:    result.Headers,
				Body:       string(result.Body),
				Duration:   result.Duration,
			}
		},
	}
}

// Post 快捷方法: 发送POST请求
func wrapPost(url string, body []byte) (*Response, error) {
	return newRequest("POST", url).SetBody(body).send()
}

// PostJSON 快捷方法: 发送JSON格式的POST请求
func wrapPostJSON(url string, data interface{}) (*Response, error) {
	req, err := newRequest("POST", url).SetJSONBody(data)
	if err != nil {
		return nil, err
	}
	return req.send()
}

// RequestModule 实现Module接口
type RequestModule struct{}

// Name 返回模块名称
func (m *RequestModule) Name() string {
	return "request"
}

// Methods 返回模块方法
func (m *RequestModule) Methods() *object.Module {
	exports := map[string]object.Object{
		"get": wrapGet(),
		/* "post":     wrapPost,
		"postJSON": wrapPostJSON, */
	}
	return &object.Module{
		Name:    "request",
		Exports: exports,
	}
}
